﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;

namespace CorporationWars
{
    [Serializable]
    public class FinancialNode : BaseNode
    {
        UIZone BuySellZone { get; set; }

        bool setCorpList { get; set; }

        ShareBuySellControl buySell { get; set; }

        WorldMapControl worldMap { get; set; }

        public FinancialNode(Game1 game)
            : base(game, "Financial", 0)
        {
            PersonelRequired = new List<SalaryLevels>(new SalaryLevels[] { SalaryLevels.Junior, SalaryLevels.Regular, SalaryLevels.Regular, SalaryLevels.Senior });
            HasExternalAccess = true;
            ShortName = "Financial";
            AddButton(new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/StockMarket", Color = Color.LimeGreen, HoverColor = Color.Lime, MouseDownColor = Color.Red, Name = "StockMarket", OnClick = ButtonClicked, ToolTipText = "Stock Market" });
            AddButton(new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Market", Color = Color.CornflowerBlue, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Market", OnClick = ButtonClicked, ToolTipText = "Property Market" });
            AddButton(new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/NodeMarket", Color = Color.CadetBlue, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Nodes", OnClick = ButtonClicked, ToolTipText = "Buy/Sell Nodes" });
            AddButton(new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Ledger", Color = Color.Purple, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Ledger", OnClick = ButtonClicked, ToolTipText = "Ledger" });
            Description = "This is where all financial details are kept.";
            Software.Add(CorporationWars.Software.CreateBasicFirewall(Game));

            AddScreenButton("StockMarket", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Back", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "ExitStock", ToolTipText = "Leave Stock Market" });
            AddScreenButton("StockMarket", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/StockMarket", Color = Color.Silver, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "HistoryLastCycle", ToolTipText = "Stock History Last Cycle" });
            AddScreenButton("StockMarket", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/StockMarket", Color = Color.SeaGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "HistoryAllTime", ToolTipText = "Stock History All Time" });
            AddScreenButton("StockMarket", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Up", Color = Color.LightGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "BuyStock", ToolTipText = "Buy Stock" });
            AddScreenButton("StockMarket", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Down", Color = Color.IndianRed, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "SellStock", ToolTipText = "Sell Stock" });

            AddScreenButton("Market", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Back", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "ExitMarket", ToolTipText = "Leave Property Market" });

            AddScreenButton("Market", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Power", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Power", ToolTipText = "Buy/Sell Power Stations" });
            AddScreenButton("Market", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Housing", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Housing", ToolTipText = "Buy/Sell Housing" });
            AddScreenButton("Market", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Factory", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Manufacure", ToolTipText = "Buy/Sell Factories" });
            AddScreenButton("Market", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Warehouse", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Warehouse", ToolTipText = "Buy/Sell Warehouses" });
            AddScreenButton("Market", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Research", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Research", ToolTipText = "Buy/Sell Research Facilities" });
            AddScreenButton("Market", new UIButton(game) { TextureAsset = "Textures/HUD/Buttons/Transport", Color = Color.LimeGreen, HoverColor = Color.White, MouseDownColor = Color.Red, Name = "Transport", ToolTipText = "Buy/Sell TransportHubs" });

            BuySellZone = new UIZone(game) { TextureAsset = "Textures/HalfShade", Color = Color.White, OpacityTolerance = .25f };

            corporationsList = new ScrollableListBox<Corporation>(Game, "CorporateNameAndSharePriceAndToken", new Vector2(422, 367), 522, 181, "Fonts/fontVSmall", false) { IsVisible = true, Closeable = false, NumberedLines = true, DecendingNumbers = true };
            corporationsList.OnSelectionChange = corpSelected;

            worldMap = new WorldMapControl(game) { Position = new Vector2(266, 200), OnButtonClicked = worldButtonClicked };

            buySell = new ShareBuySellControl(Game) { MaxValue = 999999, Font = "Fonts/fontSmall", OnButtonClicked = IncDecEnd, Position = new Vector2(400,200) };
        }

        [NonSerialized]
        List<string> ButtonsSpoken = new List<string>();

        public override void ButtonClicked(UIZone sender)
        {
            base.ButtonClicked(sender);            

            selectedCorp = null;
            ReSet();
        }

        public override void ScreenButtonClicked(UIZone sender)
        {
            base.ScreenButtonClicked(sender);
            ReSet();
            switch (selectedScreenButton)
            {
                case "ExitStock":
                case "ExitMarket":
                    selectedButton = string.Empty;
                    break;
                case "SellStock":
                case "BuyStock":
                    corporationsList.Items = null;
                    setCorpList = true;
                    break;
                case "Power":
                case "Housing":
                case "Manufacure":
                case "Warehouse":
                case "Research":
                case "Transport":
                    ShowWorldMap = true;
                    break;
            }            
        }

        public void ReSet()
        {
            scrollerVal = 0;
            selectedCorp = null;
            buySell.incDecValue = 0;
        }

        public void IncDecEnd(UIZone sender)
        {
            switch (((UIButton)sender).Name)
            {
                case "Buy":
                case "Sell":
                    makePurchase = true;                    
                    break;
                case "baseClose":
                    selectedCorp = null;
                    break;
            }
            
        }

        bool ShowWorldMap = false;
        void worldButtonClicked(UIZone sender)
        {
            switch (((UIButton)sender).Name)
            {
                case "baseClose":
                    ShowWorldMap = false;
                    selectedScreenButton = string.Empty;
                    break;
            }
        }

        bool makePurchase { get; set; }

        Corporation selectedCorp { get; set; }
        public void corpSelected(UIZone sender)
        {
            selectedCorp = corporationsList.SelectedItem;
        }

        StockEntity stockEnt { get; set; }
        public override void UpdateNode(GameTime gameTime)
        {
            scrollerVal += (Game.ScrollWheelValue * .01f);

            switch (selectedButton)
            {
                #region Stock Market
                case "StockMarket":
                    if ((selectedScreenButton == "BuyStock" || selectedScreenButton == "SellStock"))
                    {
                        BuySellZone.Update(gameTime);

                        if (setCorpList)
                        {
                            setCorpList = false;

                            if (selectedScreenButton == "BuyStock")
                            {
                                corporationsList.NumberedLines = true;
                                corporationsList.Items = Game.GlobalCorpListOrderedBySharePrice;
                            }

                            if (selectedScreenButton == "SellStock")
                            {
                                corporationsList.NumberedLines = false;
                                List<Corporation> shares = Game.GlobalCorpList.Where(entity => Game.playerCorp.StocksOwned.ContainsKey(entity.StockName)).ToList();
                                if (shares != corporationsList.Items)
                                    corporationsList.Items = shares;
                            }

                            corporationsList.ColoredItems.Add(Game.playerCorp, Color.Magenta);
                        }

                        corporationsList.Update(gameTime, Game.ScrollWheelValue * .01f);

                        if (selectedCorp != null)
                            buySell.Update(gameTime);
                    }

                    if (makePurchase)
                    {
                        makePurchase = false;
                        string desc = string.Empty;
                        switch (selectedScreenButton)
                        {
                            case "BuyStock":
                            case "SellStock":
                                if (buySell.purchaseValue > 0)
                                {
                                    stockEnt.Stocks = buySell.incDecValue;
                                    if (selectedScreenButton == "BuyStock")
                                    {
                                        if (Game.playerCorp.Funds - buySell.purchaseValue > 0)
                                        {
                                            desc = string.Format("Purchased {0} shares in {1} @ ${2:0.00} + {3:0.00}% Commission", stockEnt.Stocks, stockEnt.StockName, stockEnt.BuyPrice, Game.StockCommisionPercentage);
                                            Game.playerCorp.MakeTransaction(new FinancialTransaction() { By = Game.playerCorp, Description = desc, Value = -buySell.purchaseValue });
                                            Game.playerCorp.AddStocks(stockEnt);

                                            if (Game.AudioOn && Game.SFXOn)
                                                Game.Content.Load<SoundEffect>("Audio/SFX/kerching").Play();
                                            
                                            Game.Say("Purchase made", true);

                                            buySell.incDecValue = 0;
                                            selectedCorp = null;
                                        }
                                        else
                                        {
                                            if (Game.AudioOn && Game.SFXOn)
                                                Game.Content.Load<SoundEffect>("Audio/SFX/dupedupe").Play();
                                        }
                                    }

                                    if (selectedScreenButton == "SellStock")
                                    {
                                        desc = string.Format("Sold {0} shares in {1} @ ${2:0.00} - {3:0.00}% Commission", stockEnt.Stocks, stockEnt.StockName, stockEnt.SellPrice, Game.StockCommisionPercentage);
                                        Game.playerCorp.MakeTransaction(new FinancialTransaction() { By = Game.playerCorp, Description = desc, Value = buySell.purchaseValue });
                                        Game.playerCorp.RemoveStock(stockEnt);

                                        if(!Game.playerCorp.StocksOwned.ContainsKey(stockEnt.StockName))
                                            setCorpList = true; // re load the list..

                                        if (Game.AudioOn && Game.SFXOn)
                                            Game.Content.Load<SoundEffect>("Audio/SFX/kerching").Play();


                                        Game.Say("Sold!", true);

                                        buySell.incDecValue = 0;
                                        selectedCorp = null;
                                    }
                                }
                                else
                                {
                                    if (Game.AudioOn && Game.SFXOn)
                                        Game.Content.Load<SoundEffect>("Audio/SFX/dupedupe").Play();
                                }
                                // Adjust market acordingly.
                                break;
                        }
                    }
                    break;
                #endregion
                #region Market
                case "Market":
                    if(ShowWorldMap)
                        worldMap.Update(gameTime);
                    break;
                #endregion
            }
            


            base.UpdateNode(gameTime);
        }

        int graphBorderWidth = 0;
        
        ScrollableListBox<Corporation> corporationsList;

        public override void DrawNode(GameTime gameTime)
        {
            base.DrawNode(gameTime);

            SpriteBatch spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));

            switch (selectedButton)
            {
                #region Stock Market
                case "StockMarket":
                    float strMesure = Game.Content.Load<SpriteFont>("Fonts/font").MeasureString("Stock Market").X;
                    Game.RenderText("Stock Market", new Vector2(nodeScreenCenter - (strMesure / 2), nodeScreenTop), Color.Gold);


                    int top = nodeScreenTop + Game.Content.Load<SpriteFont>("Fonts/font").LineSpacing;
                    int bot = (top + (nodeScreenHeight / 2)) - Game.Content.Load<SpriteFont>("Fonts/fontVSmall").LineSpacing;

                    int listTop = bot + 16;

                    Corporation corp = Game.GlobalCorpListByID[CorperationID];

                    string date = Game.getCyberDate() + " ";

                    graphBorderWidth = (int)Game.Content.Load<SpriteFont>("Fonts/fontVSmall").MeasureString(date).X;
                    spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/HalfShade"), new Rectangle(nodeScreenLeft, top, nodeScreenWidth, nodeScreenHeight / 2), Color.White);
                    spriteBatch.Draw(Game.Content.Load<Texture2D>("Textures/HalfShade"), new Rectangle(nodeScreenLeft, top, graphBorderWidth, nodeScreenHeight / 2), Color.White);

                    // Market price average..
                    DrawMarketValueGraph(gameTime, top, bot);

                    // selected corp
                    if (selectedCorp != null)
                        DrawShareGraph(gameTime, selectedCorp.ThisCycleSharePriceHistory, top, bot, true, selectedCorp.StockName, "Fonts/fontVSmall", true);
                    // you
                    DrawShareGraph(gameTime, corp.ThisCycleSharePriceHistory, top, bot, true, date);

                    switch (selectedScreenButton)
                    {
                        case "HistoryLastCycle":
                            if (corp.SharePriceHistory.ContainsKey(Game.getLastCyberDate()))
                                DrawShareGraph(gameTime, corp.SharePriceHistory[Game.getLastCyberDate()], top, bot, false, Game.getLastCyberDate() + " ");
                            break;
                        case "HistoryAllTime":
                            foreach (string keyDate in corp.SharePriceHistory.Keys)
                                DrawShareGraph(gameTime, corp.SharePriceHistory[keyDate], top, bot, false, keyDate + " ");
                            break;
                        case "BuyStock":                        
                            // Display ALL the available corpoations.
                            int rating = Game.GlobalCorpListOrderedBySharePrice.IndexOf(Game.playerCorp) + 1;
                            rating = Game.GlobalCorpListOrderedBySharePrice.Count - rating;
                            string buyTitle = string.Format("Buy Stock - You are rated {0} of {1}", rating, Game.GlobalCorpListOrderedBySharePrice.Count);
                            strMesure = Game.Content.Load<SpriteFont>("Fonts/font").MeasureString(buyTitle).X;
                            Game.RenderText(buyTitle, new Vector2(nodeScreenCenter - (strMesure / 2), listTop), Color.Gold);

                            //corporationsList.Position = Vector2.Zero;
                            corporationsList.Draw(gameTime);
                            
                            // if
                            if (selectedCorp != null)
                            {
                                stockEnt = selectedCorp.GetMyLatestStockEntity(Game.getCyberDate());
                                //DrawIncDec(gameTime, spriteBatch, stockEnt, InDecPos, true);

                                buySell.BuyingMode = true;
                                buySell.selectedStock = stockEnt;
                                buySell.MaxValue = 999999;
                                buySell.Draw(gameTime);      
                            }

                            break;

                        case "SellStock":
                            string sellTitle = "Sell Stock";

                            strMesure = Game.Content.Load<SpriteFont>("Fonts/font").MeasureString(sellTitle).X;
                            Game.RenderText(sellTitle, new Vector2(nodeScreenCenter - (strMesure / 2), listTop), Color.Gold);

                            corporationsList.Draw(gameTime);

                            if (selectedCorp != null)
                            {
                                stockEnt = Game.playerCorp.StocksOwned[selectedCorp.StockName][0].DeepCopy();
                                stockEnt.SellPrice = selectedCorp.CurrentBuySharePrice;
                                // Draw list of stock for this entity..
                                buySell.BuyingMode = false;
                                buySell.selectedStock = stockEnt;
                                buySell.MaxValue = Game.playerCorp.StocksOwned[selectedCorp.StockName][0].Stocks;
                                buySell.Draw(gameTime);  
                            }

                            break;
                    }
                    break;
                #endregion
                case "Market":
                    if (ShowWorldMap)
                        worldMap.Draw(gameTime);
                    break;
            }
        }

        float scrollerVal = 0;

        public void DrawMarketValueGraph(GameTime gameTime, int top, int bot, string fontAsset = "Fonts/fontVSmall")
        {
            string val = "";
            int cnt = 0;

            Color col = Color.Red;

            if (Game.CycleMarketValue.Count > 0)
            {
                int corpCnt = Game.GlobalCorpList.Count;

                decimal minVal = Game.GlobalCorpList.Min(entity => entity.ThisCycleSharePriceHistory.Min());
                decimal maxVal = Game.GlobalCorpList.Max(entity => entity.ThisCycleSharePriceHistory.Max());
                decimal avgVal = Game.GlobalCorpList.Average(entity => entity.ThisCycleSharePriceHistory.Average());

                int x = nodeScreenLeft;
                int y = top;

                List<Vector2> points = new List<Vector2>();
                int left = nodeScreenLeft + graphBorderWidth;
                
                col = Color.Silver;

                foreach (decimal price in Game.CycleMarketValue)
                {
                    decimal p = price;
                    
                    val = string.Format("{0:0.00}", p);

                    y = (int)MathHelper.Lerp(bot, top, (float)(p / (maxVal + minVal)));
                    //y = top;
                    x = (int)MathHelper.Lerp((float)left, (float)nodeScreenLeft + (float)nodeScreenWidth, (float)cnt / (float)Game.CycleMarketValue.Count);
                    points.Add(new Vector2(x + (Game.Content.Load<SpriteFont>(fontAsset).MeasureString(val).X / 2), y));
                    if (points.Count > 1)
                    {
                        Game.drawLine(points[points.Count - 1], points[points.Count - 2], 1, col, new Vector2(-1, 1));
                    }
                    //game.RenderText(val, new Vector2(x, y), col, -1, fontAsset);
                    cnt++;
                }

                col = Color.Gold;

                Game.RenderText("Market", new Vector2(nodeScreenLeft, points[0].Y), col, -1, fontAsset);

                Game.RenderText(string.Format("Mkt {0:0.00}", minVal), new Vector2(nodeScreenLeft, bot - 12), Color.Red, -1, fontAsset);
                Game.RenderText(string.Format("Mkt {0:0.00}", avgVal), new Vector2(nodeScreenLeft, (top + (nodeScreenHeight / 4)) + 12), Color.White, -1, fontAsset);
                Game.RenderText(string.Format("Mkt {0:0.00}", maxVal), new Vector2(nodeScreenLeft, top + 12), Color.Lime, -1, fontAsset);
            
            }
        }

        public void DrawShareGraph(GameTime gameTime, List<decimal> list, int top, int bot, bool current = true, string date = "", string fontAsset = "Fonts/fontVSmall", bool otherCorp = false)
        {
            // render prices..
            string val = "";
            int cnt = 0;
              
            Color col = Color.Red;

            if (list.Count > 0)
            {
                decimal minVal = list.Min();
                decimal maxVal = list.Max();
                decimal avgVal = list.Average();

                int x = nodeScreenLeft;
                int y = top;

                List<Vector2> points = new List<Vector2>();
                int left = nodeScreenLeft + graphBorderWidth;

                foreach (decimal price in list)
                {
                    val = string.Format("{0:0.00}", price);

                    if (current)
                        col = Color.White;
                    else
                        col = Color.Silver;
                    
                    y = (int)MathHelper.Lerp(bot, top, (float)(price / (maxVal + minVal)));
                    //y = top;
                    x = (int)MathHelper.Lerp((float)left, (float)nodeScreenLeft + (float)nodeScreenWidth, (float)cnt / (float)list.Count);
                    points.Add(new Vector2(x + (Game.Content.Load<SpriteFont>(fontAsset).MeasureString(val).X / 2), y));
                    if (points.Count > 1)
                    {
                        if (points[points.Count - 1].Y > points[points.Count - 2].Y)
                        {
                            if (current)
                                col = Color.Red;
                            else
                                col = Color.DarkRed;
                        }

                        if (points[points.Count - 1].Y < points[points.Count - 2].Y)
                        {
                            if (current)
                                col = Color.Lime;
                            else
                                col = Color.Green;
                        }

                        Game.drawLine(points[points.Count - 1], points[points.Count - 2], 1, col, new Vector2(-1, 1));
                    }
                    Game.RenderText(val, new Vector2(x, y), col, -1, fontAsset);
                    cnt++;
                }

                if (current)
                    col = Color.LightBlue;
                else
                    col = Color.BlueViolet;

                Game.RenderText(date, new Vector2(nodeScreenLeft, points[0].Y), col, -1, fontAsset);

                if (current)
                {
                    if (!otherCorp)
                    {
                        Game.RenderText(string.Format("Min {0:0.00}", minVal), new Vector2(nodeScreenLeft, bot), Color.Red, -1, fontAsset);
                        Game.RenderText(string.Format("Avg {0:0.00}", avgVal), new Vector2(nodeScreenLeft, (top + (nodeScreenHeight / 4))), Color.White, -1, fontAsset);
                        Game.RenderText(string.Format("Max {0:0.00}", maxVal), new Vector2(nodeScreenLeft, top), Color.Lime, -1, fontAsset);
                    }
                    else
                    {
                        Game.RenderText(string.Format("Min {0:0.00}", minVal), new Vector2(nodeScreenLeft, bot - (Game.Content.Load<SpriteFont>(fontAsset).LineSpacing * 2)), Color.Red, -1, fontAsset);
                        Game.RenderText(string.Format("Avg {0:0.00}", avgVal), new Vector2(nodeScreenLeft, (top + (nodeScreenHeight / 4) - (Game.Content.Load<SpriteFont>(fontAsset).LineSpacing * 1))), Color.White, -1, fontAsset);
                        Game.RenderText(string.Format("Max {0:0.00}", maxVal), new Vector2(nodeScreenLeft, top + (Game.Content.Load<SpriteFont>(fontAsset).LineSpacing * 2)), Color.Lime, -1, fontAsset);
                    }
                }
            }
        }

        public override void ReWire(Game1 game)
        {
            base.ReWire(game);

            corporationsList.ReWire(game);
            buySell.ReWire(game);

            worldMap.ReWire(game);
        }

        public override void UnWire()
        {
            base.UnWire();

            corporationsList.UnWire();
            buySell.UnWire();
            worldMap.UnWire();
        }
    }
}